using DataAnalyticsTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace DataAnalyticsTools.Core.AnomalyPointDetect
{
    /// <summary>
    /// IQR (Interquartile Range) 四分位距异常检测器
    /// 基于箱线图原理，使用四分位距识别异常值
    /// 适用于有偏分布的时间序列数据，对异常值更稳健
    /// </summary>
    public static class IQRDetector
    {
        /// <summary>
        /// 使用IQR方法检测时间序列中的异常点
        /// </summary>
        /// <param name="data">时间序列数据（一维数组）</param>
        /// <param name="multiplier">IQR倍数，默认1.5（标准箱线图），值越大越不敏感</param>
        /// <returns>异常检测结果</returns>
        /// <example>
        /// 输入:
        ///   data = [10, 11, 10.5, 10.2, 50, 10.3, 10.1]  // 50是异常点
        ///   multiplier = 1.5
        /// 输出:
        ///   AnomalyPoints = [Index: 4, Value: 50]  // 索引4（值50）超出上限被识别为异常
        /// </example>
        public static AnomalyInfo Detect(
            float[] data,
            float multiplier = 1.5f)
        {
            if (data == null || data.Length == 0)
            {
                return new AnomalyInfo
                {
                    Method = "IQR",
                    AnomalyScores = Array.Empty<float>(),
                    Threshold = multiplier,
                    AnomalyPoints = new List<AnomalyPoint>(),
                    BaselineValues = Array.Empty<float>(),
                    UpperBounds = Array.Empty<float>(),
                    LowerBounds = Array.Empty<float>()
                };
            }

            int n = data.Length;
            var sortedData = data.OrderBy(x => x).ToArray();

            // 计算四分位数
            float q1 = CalculatePercentile(sortedData, 25);
            float q3 = CalculatePercentile(sortedData, 75);
            float iqr = q3 - q1;
            float median = CalculatePercentile(sortedData, 50);

            // 计算上下界
            float lowerBound = q1 - multiplier * iqr;
            float upperBound = q3 + multiplier * iqr;

            // 计算异常分数（距离边界的倍数）
            var scores = new float[n];
            for (int i = 0; i < n; i++)
            {
                if (data[i] < lowerBound)
                {
                    scores[i] = (lowerBound - data[i]) / (iqr + float.Epsilon);
                }
                else if (data[i] > upperBound)
                {
                    scores[i] = (data[i] - upperBound) / (iqr + float.Epsilon);
                }
                else
                {
                    scores[i] = 0f;
                }
            }

            // 计算边界数组
            var baselineValues = Enumerable.Repeat(median, n).ToArray();
            var upperBounds = Enumerable.Repeat(upperBound, n).ToArray();
            var lowerBounds = Enumerable.Repeat(lowerBound, n).ToArray();

            // 识别异常点
            var anomalyPoints = new List<AnomalyPoint>();
            for (int i = 0; i < n; i++)
            {
                if (scores[i] > 0)
                {
                    var anomalyType = data[i] > upperBound ? AnomalyType.High : AnomalyType.Low;
                    anomalyPoints.Add(new AnomalyPoint
                    {
                        Index = i,
                        Value = data[i],
                        Score = scores[i],
                        Type = anomalyType,
                        Deviation = scores[i],
                        Reason = $"值 {data[i]:F2} 超出四分位距范围（异常倍数: {scores[i]:F2}）"
                    });
                }
            }

            // 计算总体严重程度和置信度
            var severity = anomalyPoints.Any() ? anomalyPoints.Max(p => p.Score) : 0f;

            // 置信度基于样本量和分布稳定性
            // 1. 样本量因子：样本越多越可靠 (最大到30个样本时达到1.0)
            float sampleFactor = Math.Min(1.0f, n / 30.0f);

            // 2. 稳定性因子：IQR相对于中位数越小越稳定
            float iqrRelative = iqr > float.Epsilon ? iqr / (Math.Abs(median) + 1e-6f) : 0f;
            float stabilityFactor = iqrRelative < 0.5f ? 1.0f - iqrRelative : 0.5f / (iqrRelative + 0.1f);

            // 综合置信度 = 样本量因子 * 稳定性因子
            var confidence = sampleFactor * stabilityFactor;

            return new AnomalyInfo
            {
                Method = "IQR",
                AnomalyScores = scores,
                Threshold = multiplier,
                AnomalyPoints = anomalyPoints,
                Severity = severity,
                Confidence = confidence,
                BaselineValues = baselineValues,
                UpperBounds = upperBounds,
                LowerBounds = lowerBounds
            };
        }

        private static float CalculatePercentile(float[] sortedData, float percentile)
        {
            int n = sortedData.Length;
            float position = (percentile / 100f) * (n - 1);
            int lower = (int)Math.Floor(position);
            int upper = (int)Math.Ceiling(position);

            if (lower == upper)
                return sortedData[lower];

            float fraction = position - lower;
            return sortedData[lower] * (1 - fraction) + sortedData[upper] * fraction;
        }
    }
}
